You are working for Macrohard
company in data structures department. After failing your previous task about
key insertion you were asked to write a new data structure that would be able
to return quickly k-th order
statistics in the array segment.
That is, given an array a[1 ... n] of different integer numbers, your
program must answer a series of questions Q(i,
j, k) in the form: "What would be the k-th number in a[i ... j] segment, if this segment was
sorted?"
For example, consider the array a
= (1, 5, 2, 6, 3, 7, 4). Let the question be Q(2, 5, 3). The segment a[2 ... 5]
is (5, 2, 6, 3). If we sort this segment, we get (2, 3, 5, 6), the third number
is 5, and therefore the answer to the question is 5.
Input. The first line contains n
– the size of the array, and m – the
number of questions to answer (1 ≤ n
≤ 100000, 1 ≤ m ≤
5000). The second line contains n different
integer numbers not exceeding 109 by their absolute values – the
array for which the answers should be given.
The following m lines contain question descriptions,
each description consists of three numbers: i,
j and k (1 ≤ i ≤ j ≤ n, 1 ≤ k ≤ j – i
+ 1) and represents the question Q(i,
j, k).
Output. For each question output the answer to it – the k-th number in sorted a[i ... j] segment.
Sample Input
7 3
1 5 2 6 3 7 4
2 5 3
4 4 1
1 7 3
Sample Output
5
6
3
РЕШЕНИЕ
структуры данных – дерево
отрезков
Анализ алгоритма
Заведем в каждой вершине дерева
отрезков дополнительный массив. Вершина, соответствующая фундаментальному
отрезку [i; j], содержит в своем массиве отсортированный набор чисел ai, …, aj.
Пусть запрос Query(l, r,
x) находит количество чисел из
интервала [l, r], которые меньше x. Для этого разобьем этот интервал на множество фундаментальных
отрезков, в каждом из которых совершим бинарный поиск, подсчитав число
элементов, меньших x. Время запроса
составит .
Ответ на запрос Q(i, j,
k) будем искать бинарным поиском.
Следует найти такое ap из
интервала [ai, …, aj], что Query(l, r,
ap) равно k – 1. То есть если ap является k
–ым элементов на отрезке [i; j], то количество чисел на этом отрезке,
меньших ap, равно k – 1. Принципиальным в этой задаче
является то, что все входные числа разные. Таким образом запрос выполняется за .
Реализация алгоритма
#include <cstdio>
#include <vector>
#include <algorithm>
#define MAX 100010
using namespace std;
int i, j, k, n, m, l, r, x;
int a[MAX];
vector<vector<int> > SegTree;
void build(int Vertex, int LeftPos, int
RightPos)
{
if (LeftPos == RightPos)
SegTree[Vertex].push_back(a[LeftPos]);
else
{
int Middle = (LeftPos + RightPos) / 2;
build (2*Vertex, LeftPos, Middle);
build (2*Vertex+1, Middle+1, RightPos);
SegTree[Vertex].resize(RightPos - LeftPos + 1);
merge(SegTree[2*Vertex].begin(),SegTree[2*Vertex].end(),SegTree[2*Vertex+1].begin(),SegTree[2*Vertex+1].end(),SegTree[Vertex].begin());
}
}
int Query(int Vertex, int LeftPos, int
RightPos, int Left, int
Right, int x)
{
if (Left > Right) return
0;
if ((LeftPos == Left) && (RightPos == Right))
return
lower_bound(SegTree[Vertex].begin(),SegTree[Vertex].end(),x) – SegTree[Vertex].begin();
int Middle = (LeftPos + RightPos) / 2;
return Query(2*Vertex, LeftPos, Middle, Left,
min(Middle,Right), x) +
Query(2*Vertex+1, Middle+1, RightPos, max(Left,Middle+1), Right, x);
}
int main(void)
{
scanf("%d %d",&n,&m);
for(i = 1; i <= n; i++)
scanf("%d",&a[i]);
SegTree.resize(4*n);
build(1,1,n);
sort(a+1,a+n+1);
while(m--)
{
scanf("%d
%d %d",&i,&j,&k);
int ll = 1, rr = n;
while(rr - ll > 1)
{
int mid = (ll + rr) / 2;
if(Query(1,1,n,i,j,a[mid]) < k)
ll = mid;
else
rr = mid;
}
if(Query(1,1,n,i,j,a[ll]+1) >= k)
printf("%d\n",a[ll]);
else
printf("%d\n",a[rr]);
}
return 0;
}